package atom.core3.hibernate.jpa;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.log4j.Logger;

import atom.core0.jdbc.SqlUtil;
import atom.core0.object.ClassUtil;

public class AnnotationUtil {
	protected final static Logger logger = Logger.getLogger(AnnotationUtil.class);
	public static List mapListToBeanList(Class myClass, List<Map> listMap) throws Exception
	{
		List list = new ArrayList();
		for (int i = 0; i < listMap.size(); i++)
		{
			Object obj = mapToBean(myClass, listMap.get(i));
			list.add(obj);
		}
		return list;
	}

	public static Object mapToBean(Class myClass, Map map) throws Exception
	{
		DBAnnotation dbAnnotation = DBAnnotationManager.scanDBAnnotation(myClass);
		Object obj = myClass.newInstance();
		Iterator itt = map.entrySet().iterator();
		while (itt.hasNext())
		{
			Map.Entry entry = (Map.Entry) itt.next();
			String key = (String) entry.getKey();
			Object value = entry.getValue();
			// 普通字段
			DBFieldAnnotation dbField = dbAnnotation.getFieldAnnotationMap().get(key);
			if (dbField != null)
			{
				try
				{
					dbField.getSetMethod().invoke(obj, new Object[] { value });
				}
				catch (Throwable e)
				{
					logger.warn("mapToBean:动态设置"+dbField.getBeanField()+"的值为"+value+"出错"+e.getMessage());
				}
				continue;
			}
			// 复合主键
			DBFieldAnnotation keyField = dbAnnotation.getKeyAnnotationMap().get(key);
			if (keyField != null)
			{
				Object keyObject;
				keyObject = dbAnnotation.getBeanKey().getGetMethod().invoke(obj, new Object[] {});
				if (keyObject == null)
				{
					keyObject = dbAnnotation.getBeanKey().getReturnType().newInstance();
					dbAnnotation.getBeanKey().getSetMethod().invoke(obj, new Object[] { keyObject });;
				}
				try
				{
					keyField.getSetMethod().invoke(keyObject, new Object[] { value });
				}
				catch (Throwable e)
				{
					logger.warn("mapToBean:动态设置"+keyField.getBeanField()+"的值为"+value+"出错"+e.getMessage());
				}
				
				continue;
			}

		}

		return obj;
	}
	
	public static DBAnnotation scanDBAnnotation(Class myClass) 
	{
		DBAnnotation dbAnnotation = new DBAnnotation();
		//表名
		Table tableAnnotation = (Table) myClass.getAnnotation(Table.class);
		if (tableAnnotation != null)
		{
			String tableName = tableAnnotation.name();
			dbAnnotation.setTableName(tableName);
			logger.debug("Bean扫描[" + myClass.getName() + "]表名:" + tableName);
		}
		//字段
		Map fieldMap = dbAnnotation.getFieldAnnotationMap();
		Map keyMap = dbAnnotation.getKeyAnnotationMap();
		Map<String,Method> methodMap = ClassUtil.getMethodMap(myClass,"get");
		
		//LinkedHashMap myMap = new LinkedHashMap();
		Iterator it=methodMap.entrySet().iterator();
		while(it.hasNext()){
		    Map.Entry entry=(Map.Entry)it.next();
		    String beanField = (String)entry.getKey();
		    Method getMethod = (Method)entry.getValue();
		    //复合主键
		    boolean hasEmbeddedId=getMethod.isAnnotationPresent(EmbeddedId.class) ;
		    if (hasEmbeddedId)
		    {
		    	DBFieldAnnotation beanKey = new DBFieldAnnotation();
		    	dbAnnotation.setBeanKey(beanKey);

		    	beanKey.setBeanField(beanField);
		    	beanKey.setGetMethod(getMethod);
		    	//beanKey.setSetMethod(setMethod);
		    	beanKey.setReturnType(getMethod.getReturnType());
		    	
		    	//dbAnnotation.setBeanKey(beanField);
		    	//dbAnnotation.setBeanKeyGetMethod(getMethod);
				Method setMethod1	 = ClassUtil.getSetMethod(myClass,beanField,new Class[]{getMethod.getReturnType()});
				beanKey.setSetMethod(setMethod1);
				//dbAnnotation.setBeanKeySetMethod(setMethod1);
		    	
		    	Class keyClass = getMethod.getReturnType();
		    	DBAnnotation keyDBAnnotation= scanDBAnnotation(keyClass);
				Iterator itt=keyDBAnnotation.getFieldAnnotationMap().entrySet().iterator();
				while(itt.hasNext()){
				    entry=(Map.Entry)itt.next();
				    String key = (String)entry.getKey();
				    DBFieldAnnotation keyFieldAnnotation = (DBFieldAnnotation)entry.getValue();
				    //fieldMap.put(key, keyFieldAnnotation);
				    keyMap.put(key, keyFieldAnnotation);
				}			

		    }
		    boolean hasAnnotation=getMethod.isAnnotationPresent(Column.class) ;
		    if (!hasAnnotation)
		    	continue;
			//Blob类型丢弃
			if(getMethod.getReturnType().equals(Blob.class))
				continue;
		    
		    Column column = getMethod.getAnnotation(Column.class);
		    String dbField = column.name();
		    
			DBFieldAnnotation dbFieldAnnotation = new DBFieldAnnotation();
			dbFieldAnnotation.setBeanField(beanField);
			dbFieldAnnotation.setDbField(dbField);
			dbFieldAnnotation.setGetMethod(getMethod);
			dbFieldAnnotation.setReturnType(getMethod.getReturnType());
			
			Method setMethod = ClassUtil.getSetMethod(myClass,beanField,new Class[]{getMethod.getReturnType()});
			dbFieldAnnotation.setSetMethod(setMethod);
		    //主键
		    boolean hasId=getMethod.isAnnotationPresent(Id.class) ;
		    if (hasId)
		    {
		    	keyMap.put(beanField, dbFieldAnnotation);
		    }
		    else
		    {
		    	fieldMap.put(beanField, dbFieldAnnotation);
		    }
			logger.debug("Bean扫描["+myClass.getName()+"]字段:"+dbFieldAnnotation.getBeanField()+","+dbFieldAnnotation.getDbField()+","+dbFieldAnnotation.getReturnType().getName());
		}	
		
		return dbAnnotation;
	}	
	public static String getInsertSql(Serializable bean,String tableSuffix) throws Exception
	{
		DBAnnotation dbAnnotation  = DBAnnotationManager.scanDBAnnotation(bean.getClass());
		String tableName;
		if (tableSuffix==null)
			tableName = dbAnnotation.getTableName();
		else
			tableName = dbAnnotation.getTableName()+tableSuffix;
		
		LinkedHashMap myMap = new LinkedHashMap();

		//如果主键
		Map<String,DBFieldAnnotation> keyMap = dbAnnotation.getKeyAnnotationMap();
		Iterator it=keyMap.entrySet().iterator();
		while(it.hasNext()){
		    Map.Entry entry=(Map.Entry)it.next();
		    String beanField = (String)entry.getKey();
		    DBFieldAnnotation dbFieldAnnotation = (DBFieldAnnotation)entry.getValue();
		    Method getMethod = dbFieldAnnotation.getGetMethod();
		    String dbField = dbFieldAnnotation.getDbField();
		    Object value;
			//Object value = ClassUtil.invokeGetMethod(bean,beanField);
		    //普通主键
		    if(dbAnnotation.getBeanKey() ==null)
		    {
				value = getMethod.invoke(bean);
		    	
		    }
		    //如果是复合主键
		    else
			{
				Method keyGetMethod = dbAnnotation.getBeanKey().getGetMethod();
				Object keyobj = keyGetMethod.invoke(bean, new Object[] {});
				if (keyobj==null)
					value=null;
				else
					value = getMethod.invoke(keyobj, new Object[] {});
			}

			myMap.put(dbField, value);
		}
		//普通字段
		Map<String,DBFieldAnnotation> fieldMap = dbAnnotation.getFieldAnnotationMap();
		it=fieldMap.entrySet().iterator();
		while(it.hasNext()){
		    Map.Entry entry=(Map.Entry)it.next();
		    String beanField = (String)entry.getKey();
		    DBFieldAnnotation dbFieldAnnotation = (DBFieldAnnotation)entry.getValue();
		    Method getMethod = dbFieldAnnotation.getGetMethod();
		    String dbField = dbFieldAnnotation.getDbField();
		    Object value;
		    value = getMethod.invoke(bean, new Object[] {});

			//都是 insert 没有必要防sql注入
			//if (value instanceof String)
			//	value = ((String)value).replace("'", " ");
			myMap.put(dbField, value);
		}				
		String sql = SqlUtil.getInsertSql("", tableName, myMap);
		return sql;
	}

}
